From ee06ce951b9ede937ca9676dc1b750cf65f3ecbe Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 19 Sep 2008 13:45:07 +0000 Subject: [PATCH] =?utf8?q?Bug=2083935=20=E2=80=93=20GtkEntry's=20default?= =?utf8?q?=20invisible=20char=20should=20be=20U+25CF?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 2008-09-19 Carlos Garnacho Bug 83935 – GtkEntry's default invisible char should be U+25CF * gtk/gtkentry.c (find_invisible_char) (gtk_entry_init): Find a more suitable invisible char than '*' based on the used font. (gtk_entry_class_init) (gtk_entry_set_property) (gtk_entry_get_property): Add a "invisible-char-set" property. (gtk_entry_unset_invisible_char): New function, needed now that the default invisible char isn't fixed. * gtk/gtkentry.h: * gtk/gtk.symbols: * docs/reference/gtk/gtk-sections.txt: Add the new function. svn path=/trunk/; revision=21446 --- ChangeLog | 14 +++ docs/reference/gtk/gtk-sections.txt | 1 + gtk/gtk.symbols | 1 + gtk/gtkentry.c | 137 ++++++++++++++++++++++++++-- gtk/gtkentry.h | 1 + 5 files changed, 144 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index cc01bbe78d..487d6a2a80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2008-09-19 Carlos Garnacho + + Bug 83935 – GtkEntry's default invisible char should be U+25CF + + * gtk/gtkentry.c (find_invisible_char) (gtk_entry_init): Find a + more suitable invisible char than '*' based on the used font. + (gtk_entry_class_init) (gtk_entry_set_property) + (gtk_entry_get_property): Add a "invisible-char-set" property. + (gtk_entry_unset_invisible_char): New function, needed now that the + default invisible char isn't fixed. + * gtk/gtkentry.h: + * gtk/gtk.symbols: + * docs/reference/gtk/gtk-sections.txt: Add the new function. + 2008-09-19 Christian Persch Bug 552837 – mem leak in gtkimmulticontext diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt index 47ffd723b8..8c854ee201 100644 --- a/docs/reference/gtk/gtk-sections.txt +++ b/docs/reference/gtk/gtk-sections.txt @@ -1228,6 +1228,7 @@ gtk_entry_get_text_length gtk_entry_select_region gtk_entry_set_visibility gtk_entry_set_invisible_char +gtk_entry_unset_invisible_char gtk_entry_set_editable gtk_entry_set_max_length gtk_entry_get_activates_default diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index c517106022..1d68fec073 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -1299,6 +1299,7 @@ gtk_entry_set_width_chars gtk_entry_text_index_to_layout_index gtk_entry_set_cursor_hadjustment gtk_entry_get_cursor_hadjustment +gtk_entry_unset_invisible_char #endif #endif diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index 76d17b64ab..7aed86e312 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -87,6 +87,7 @@ struct _GtkEntryPrivate guint blink_time; /* time in msec the cursor has blinked since last user event */ guint interior_focus : 1; guint real_changed : 1; + guint invisible_char_set : 1; guint change_count : 8; gint focus_width; @@ -135,7 +136,8 @@ enum { PROP_TRUNCATE_MULTILINE, PROP_SHADOW_TYPE, PROP_OVERWRITE_MODE, - PROP_TEXT_LENGTH + PROP_TEXT_LENGTH, + PROP_INVISIBLE_CHAR_SET }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -664,6 +666,20 @@ gtk_entry_class_init (GtkEntryClass *class) G_MAXUINT16, 0, GTK_PARAM_READABLE)); + /** + * GtkEntry:invisible-char-set: + * + * Whether the invisible char has been set for the #GtkEntry. + * + * Since: 2.16 + */ + g_object_class_install_property (gobject_class, + PROP_INVISIBLE_CHAR_SET, + g_param_spec_boolean ("invisible-char-set", + P_("Invisible char set"), + P_("Whether the invisible char has been set"), + FALSE, + GTK_PARAM_READWRITE)); signals[POPULATE_POPUP] = g_signal_new (I_("populate-popup"), @@ -1063,6 +1079,13 @@ gtk_entry_set_property (GObject *object, gtk_entry_set_overwrite_mode (entry, g_value_get_boolean (value)); break; + case PROP_INVISIBLE_CHAR_SET: + if (g_value_get_boolean (value)) + priv->invisible_char_set = TRUE; + else + gtk_entry_unset_invisible_char (entry); + break; + case PROP_SCROLL_OFFSET: case PROP_CURSOR_POSITION: default: @@ -1133,13 +1156,57 @@ gtk_entry_get_property (GObject *object, case PROP_TEXT_LENGTH: g_value_set_uint (value, entry->text_length); break; - + case PROP_INVISIBLE_CHAR_SET: + g_value_set_boolean (value, priv->invisible_char_set); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } +static gunichar +find_invisible_char (GtkWidget *widget) +{ + PangoLayout *layout; + PangoAttrList *attr_list; + gint i; + gunichar invisible_chars [] = { + 0x25cf, /* BLACK CIRCLE */ + 0x2022, /* BULLET */ + 0x2731, /* HEAVY ASTERISK */ + 0x273a /* SIXTEEN POINTED ASTERISK */ + }; + + layout = gtk_widget_create_pango_layout (widget, NULL); + + attr_list = pango_attr_list_new (); + pango_attr_list_insert (attr_list, pango_attr_fallback_new (FALSE)); + + pango_layout_set_attributes (layout, attr_list); + pango_attr_list_unref (attr_list); + + for (i = 0; i < G_N_ELEMENTS (invisible_chars); i++) + { + gchar text[7] = { 0, }; + gint len, count; + + len = g_unichar_to_utf8 (invisible_chars[i], text); + pango_layout_set_text (layout, text, len); + + count = pango_layout_get_unknown_glyphs_count (layout); + + if (count == 0) + { + g_object_unref (layout); + return invisible_chars[i]; + } + } + + g_object_unref (layout); + return '*'; +} + static void gtk_entry_init (GtkEntry *entry) { @@ -1153,7 +1220,7 @@ gtk_entry_init (GtkEntry *entry) entry->editable = TRUE; entry->visible = TRUE; - entry->invisible_char = '*'; + entry->invisible_char = find_invisible_char (GTK_WIDGET (entry)); entry->dnd_position = -1; entry->width_chars = -1; entry->is_cell_renderer = FALSE; @@ -2441,7 +2508,10 @@ gtk_entry_style_set (GtkWidget *widget, priv->focus_width = focus_width; priv->interior_focus = interior_focus; - + + if (!priv->invisible_char_set) + entry->invisible_char = find_invisible_char (GTK_WIDGET (entry)); + gtk_entry_recompute (entry); if (previous_style && GTK_WIDGET_REALIZED (widget)) @@ -4548,8 +4618,9 @@ gtk_entry_set_position (GtkEntry *entry, * as the invisible char, and will also appear that way when * the text in the entry widget is copied elsewhere. * - * The default invisible char is the asterisk '*', but it can - * be changed with gtk_entry_set_invisible_char(). + * By default, GTK+ picks the best invisible character available + * in the current font, but it can be changed with + * gtk_entry_set_invisible_char(). */ void gtk_entry_set_visibility (GtkEntry *entry, @@ -4615,17 +4686,27 @@ gtk_entry_get_visibility (GtkEntry *entry) * Sets the character to use in place of the actual text when * gtk_entry_set_visibility() has been called to set text visibility * to %FALSE. i.e. this is the character used in "password mode" to - * show the user how many characters have been typed. The default - * invisible char is an asterisk ('*'). If you set the invisible char - * to 0, then the user will get no feedback at all; there will be - * no text on the screen as they type. + * show the user how many characters have been typed. By default, GTK+ + * picks the best invisible char available in the current font. If you + * set the invisible char to 0, then the user will get no feedback + * at all; there will be no text on the screen as they type. **/ void gtk_entry_set_invisible_char (GtkEntry *entry, gunichar ch) { + GtkEntryPrivate *priv; + g_return_if_fail (GTK_IS_ENTRY (entry)); + priv = GTK_ENTRY_GET_PRIVATE (entry); + + if (!priv->invisible_char_set) + { + priv->invisible_char_set = TRUE; + g_object_notify (G_OBJECT (entry), "invisible-char-set"); + } + if (ch == entry->invisible_char) return; @@ -4652,6 +4733,42 @@ gtk_entry_get_invisible_char (GtkEntry *entry) return entry->invisible_char; } +/** + * gtk_entry_unset_invisible_char: + * @entry: a #GtkEntry + * + * Unsets the invisible char previously set with + * gtk_entry_set_invisible_char(). So that the + * default invisible char is used again. + * + * Since: 2.16 + **/ +void +gtk_entry_unset_invisible_char (GtkEntry *entry) +{ + GtkEntryPrivate *priv; + gunichar ch; + + g_return_if_fail (GTK_IS_ENTRY (entry)); + + priv = GTK_ENTRY_GET_PRIVATE (entry); + + if (!priv->invisible_char_set) + return; + + priv->invisible_char_set = FALSE; + ch = find_invisible_char (GTK_WIDGET (entry)); + + if (entry->invisible_char != ch) + { + entry->invisible_char = ch; + g_object_notify (G_OBJECT (entry), "invisible-char"); + } + + g_object_notify (G_OBJECT (entry), "invisible-char-set"); + gtk_entry_recompute (entry); +} + /** * gtk_entry_set_editable: * @entry: a #GtkEntry diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h index 2019b1eee6..ca9282831f 100644 --- a/gtk/gtkentry.h +++ b/gtk/gtkentry.h @@ -160,6 +160,7 @@ gboolean gtk_entry_get_visibility (GtkEntry *entry); void gtk_entry_set_invisible_char (GtkEntry *entry, gunichar ch); gunichar gtk_entry_get_invisible_char (GtkEntry *entry); +void gtk_entry_unset_invisible_char (GtkEntry *entry); void gtk_entry_set_has_frame (GtkEntry *entry, gboolean setting); gboolean gtk_entry_get_has_frame (GtkEntry *entry); -- 2.30.2